package cn.akwangl.spring.dependency.lookup;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * {@link HierarchicalBeanFactory} Spring Bean 层次性 Demo
 * 1. {@link ConfigurableListableBeanFactory#setParentBeanFactory(BeanFactory)} 使用
 * 2. BeanFactory 层次关系演示
 *
 * @author youyongkun
 * @date 2021/7/4 20:53
 */
public class HierarchicalDependencyLookupDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(HierarchicalDependencyLookupDemo.class);
        applicationContext.refresh();

        HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
        ConfigurableListableBeanFactory configurableListableBeanFactory = applicationContext.getBeanFactory();
        configurableListableBeanFactory.setParentBeanFactory(parentBeanFactory);
        // 继承关系: HierarchicalBeanFactory--> ListableBeanFactory --> ConfigurableListableBeanFactory
        // 故: ConfigurableListableBeanFactory == HierarchicalBeanFactory
        HierarchicalBeanFactory beanFactory = applicationContext.getBeanFactory();
        System.out.println("当前BeanFactor 上一级节点: " + beanFactory.getParentBeanFactory());

        displayContainsLocalBean(beanFactory, "user");
        displayContainsLocalBean(parentBeanFactory, "user");

        displayContainsBean(beanFactory, "user");
        displayContainsBean(parentBeanFactory, "user");


        applicationContext.close();
    }

    private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.printf("当前 BeanFactory[%s] 是否包含 Bean[name : %s] : %s\n", beanFactory, beanName,
                containsBean(beanFactory, beanName));
    }

    private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) {
        if (beanFactory.containsBean(beanName)) {
            return true;
        } else {
            BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
            if (parentBeanFactory instanceof HierarchicalBeanFactory) {
                HierarchicalBeanFactory hierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
                return hierarchicalBeanFactory.containsLocalBean(beanName);
            }
        }
        return containsBean(beanFactory, beanName);
    }

    private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.printf("当前 BeanFactory[%s] 是否包含 Local Bean[name : %s] : %s\n", beanFactory, beanName,
                beanFactory.containsLocalBean(beanName));
    }


    private static ConfigurableListableBeanFactory createParentBeanFactory() {
        // 创建 BeanFactory 容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // XML 配置文件 ClassPath 路径
        String location = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载配置
        reader.loadBeanDefinitions(location);
        return beanFactory;
    }


}
